#include "ContainerNode.h"
#include "AnimatePropertyNode.h"
#include <QPainter>
#include <QtAlgorithms>
#include <cmath>
#include "PathNode.h"
#include "RectNode.h"
#include "PictureNode.h"
#include "SymbolNode.h"
#include "MovieClipNode.h"
#include "EclipseNode.h"
#include "WordShapeNode.h"
//Begin section for file ContainerNode.cpp
//TODO: Add definitions that you want preserved
//End section for file ContainerNode.cpp

int ContainerNode::SymbolCount=0;

ContainerNode::ContainerNode()
	:Visible(new AnimatePropertyNode(1)),symbolID(SymbolCount++)
	,children()
{
}

ContainerNode::ContainerNode(const ContainerNode & arg) 
	:DisplayNode(arg),Visible(new AnimatePropertyNode(*((AnimatePropertyNode*)arg.Visible))),symbolID(SymbolCount++)
	,children()
{
		for(int i=0;i!=arg.children.size();++i)
			switch(arg.children[i]->NodeType())
			{
			case Path:
				children.append(new PathNode (* ( (PathNode*)(arg.children[i]) ) ) );
				break;
			case Picture:
				children.append(new PictureNode (* ( (PictureNode*)(arg.children[i]) ) ) );
				break;
			case Rect:
				children.append(new RectNode (* ( (RectNode*)(arg.children[i]) ) ) );
				break;
			case Eclipse:
				children.append(new EclipseNode (* ( (EclipseNode*)(arg.children[i]) ) ) );
				break;
			case WordShape:
				children.append(new WordShapeNode (* ( (WordShapeNode*)(arg.children[i]) ) ) );
				break;
			case MovieClip:
				children.append(new MovieClipNode (* ( (MovieClipNode*)(arg.children[i]) ) ) );
				break;
			case Symbol:
				children.append(new SymbolNode (* ( (SymbolNode*)(arg.children[i]) ) ) );
				break;
			}
}


void ContainerNode::CopyProperty(DisplayNode* ref)
{
	if(PosX)
		delete PosX;
	if(PosY)
		delete PosY;
	if(AxisX)
		delete AxisX;
	if(AxisY)
		delete AxisY;
	if(ScaleX)
		delete ScaleX;
	if(ScaleY)
		delete ScaleY;
	if(SkewX)
		delete SkewX;
	if(SkewY)
		delete SkewY;
	if(RotationAngle)
		delete RotationAngle;	
	if(Alpha)
		delete Alpha;
	if(ref->IsAtomic())
	{
		PosX=new AnimatePropertyNode(ref->GetPosX());
		PosY=new AnimatePropertyNode(ref->GetPosY());
		AxisX=new AnimatePropertyNode(ref->GetAxisX());
		AxisY=new AnimatePropertyNode(ref->GetAxisY());
		ScaleX=new AnimatePropertyNode(ref->GetScaleX());
		ScaleY=new AnimatePropertyNode(ref->GetScaleY());
		SkewX=new AnimatePropertyNode(ref->GetSkewX());
		SkewY=new AnimatePropertyNode(ref->GetSkewY());
		RotationAngle=new AnimatePropertyNode(ref->GetAngle());
		Alpha=new AnimatePropertyNode(ref->GetAlpha());
	}
	else
	{
		if(Visible)
			delete Visible;
		Visible=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->Visible)  );
		PosX=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->PosX)  );
		PosY=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->PosY)  );
		AxisX=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->AxisX)  );
		AxisY=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->AxisY)  );
		ScaleX=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->ScaleX)  );
		ScaleY=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->ScaleY)  );
		SkewX=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->SkewX)  );
		SkewY=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->SkewY)  );
		RotationAngle=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->RotationAngle)  );
		Alpha=new AnimatePropertyNode(  *(AnimatePropertyNode*)(((ContainerNode *)ref)->Alpha)  );
	}
	dirty=true;
}

ContainerNode::~ContainerNode() 
{
	for(int i=0;i!=children.size();++i)
		if(children[i])
			delete children[i];
}

void ContainerNode::AddChildren(DisplayNode * np,int index) 
{
	if(index<0||index>=children.size())
		children.append(np);
	else
		children.insert(index,np);
	dirty=true;
    return;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
void ContainerNode::RemoveChildrenAt(int index)
{
	if(index<0||index>=children.size())
		return;
	delete children[index];
	children.remove(index);
	dirty=true;
    return;
}
void ContainerNode::ReplaceChildrenAt(int index,DisplayNode * another)
{
	if(index<0||index>=children.size())
		return;
	delete children[index];
	children[index]=another;
	dirty=true;
}
DisplayNode * ContainerNode::PopChildrenAt(int index)
{
	if(index<0||index>=children.size())
		return 0;
	DisplayNode *ret= children[index];
	children.remove(index);
	dirty=true;
	return ret;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int ContainerNode::IndexOf(DisplayNode * np)
{

    return children.indexOf(np);
}

void ContainerNode::Swap(int i1,int i2)
{
	if(i1<0||i1>=children.size())
		return;
	if(i2<0||i2>=children.size())
		return;
	DisplayNode * temp=children[i1];
	children[i1]=children[i2];
	children[i2]=temp;
	dirty=true;
}
DisplayNode* ContainerNode::ChildrenAt(int index)
{
	if(index<0||index>=children.size())
		return 0;
	return children[index];
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
QVector<int> ContainerNode::GetChildrenUnderPoint(QPointF pt) 
{
	QVector<int> result;
	for(int i=0;i!=children.size();++i)
		if(children[i]->IsPointIn(pt.x(),pt.y()))
			result.append(i);
    return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int ContainerNode::GetChildUnderPoint(QPointF pt) 
{
	for(int i=0;i!=children.size();++i)
		if(children[i]->IsPointIn(pt.x(),pt.y()))
			return i;
    return -1;
}



void ContainerNode::SetVisible(double a,int time,Ease::EaseType type)
{
	if(a!=0&&a!=1)
		return;
	Visible->SetValue(time,a,type);
	dirty=true;
}

void ContainerNode::UpdateCache ()
{
	if(dirty)
	{
		if(CacheImage)
		{
			delete CacheImage;
			CacheImage=0;
		}
		if(!children.size())
		{
			CacheImage=new QImage();
			return;
		}
		QRectF boundary;
		QVector<QTransform>temp;
		for(int i=0;i!=children.size();++i)
		{
			children[i]->UpdateCache();
			QTransform trans;
			double posx=children[i]->GetPosX();
			double posy=children[i]->GetPosY();
			double sx=children[i]->GetScaleX();
			double sy=children[i]->GetScaleY();
			double ax=children[i]->GetAxisX();
			double ay=children[i]->GetAxisY();
			double sh=children[i]->GetSkewX()/180*3.14159;
			double sv=children[i]->GetSkewY()/180*3.14159;
			double a=children[i]->GetAngle()/180*3.14159;
			QRectF rect(children[i]->CacheOffsetX(),
				children[i]->CacheOffsetY(),
				children[i]->GetWidth(),
				children[i]->GetHeight());
			//trans.translate(posx,posy);
			trans=QTransform(cos(sv), sin(sv), -sin(sh), cos(sh),posx,posy)*trans;
			//trans.rotateRadians(a);
			trans=QTransform(cos(a)*sx, sin(a)*sx, -sin(a)*sy, cos(a)*sy,0,0)*trans;//.rotate(a);
			//trans.scale(sx,sy);
			trans=QTransform(1,0, 0,1,-ax,-ay)*trans;//trans.translate(-ax,-ay);
			temp.append(trans);
			boundary=boundary.united(temp.last().map(QPolygonF(rect)).boundingRect() );
			trans.reset();
		}
		CacheImage=new QImage(boundary.width()+1,boundary.height()+1,QImage::Format_ARGB32);
		CacheImage->fill(0);
		cacheOffsetX=boundary.x();
		cacheOffsetY=boundary.y();
        Width=boundary.width();
        Height=boundary.height();
		QPainter ctx(CacheImage);
		ctx.setRenderHints(QPainter::Antialiasing);
		ctx.setRenderHints(QPainter::HighQualityAntialiasing);
		ctx.setRenderHints(QPainter::SmoothPixmapTransform);
		ctx.translate(-cacheOffsetX,-cacheOffsetY);
		for(int i=0;i!=children.size();++i)
		{
			ctx.save();
			ctx.setTransform(temp[i],true);
			ctx.drawImage(children[i]->CacheOffsetX(),
				children[i]->CacheOffsetY(),
				children[i]->GetImage());
			ctx.restore();
		}
		ctx.setCompositionMode(QPainter::CompositionMode_DestinationIn);
		ctx.fillRect(boundary, QColor(0, 0, 0, Alpha->ValueOnCurrentTime(0)*255));
		dirty=false;
	}
}
bool ContainerNode::IsPointIn(double PosX,double PosY)const
{
	for(int i=0;i!=children.size();++i)
	{		
		QTransform trans;
		double posx=children[i]->GetPosX();
		double posy=children[i]->GetPosY();
		double sx=children[i]->GetScaleX();
		double sy=children[i]->GetScaleY();
		double ax=children[i]->GetAxisX();
		double ay=children[i]->GetAxisY();
		double sh=children[i]->GetSkewX()/180*3.14159;
		double sv=children[i]->GetSkewY()/180*3.14159;
		double a=children[i]->GetAngle()/180*3.14159;
		///trans.translate(posx,posy);
			trans=QTransform(cos(sv), sin(sv), -sin(sh), cos(sh),posx,posy)*trans;
			//trans.rotateRadians(a);
			trans=QTransform(cos(a)*sx, sin(a)*sx, -sin(a)*sy, cos(a)*sy,0,0)*trans;//.rotate(a);
			//trans.scale(sx,sy);
			trans=QTransform(1,0, 0,1,-ax,-ay)*trans;//trans.translate(-ax,-ay);
		trans=trans.inverted();
		QPointF p=trans.map(QPointF(PosX,PosY));
		if(children[i]->IsPointIn(p.x(),p.y()))
			return true;
	}
	return false;
}
QVector<int > ContainerNode::getKeyFrames(int flags)const
{
	QVector<int> temp;
	if(flags&1)
		temp+=this->PosX->KeyFrames();
	flags>>=1;
	if(flags&1)
		temp+=this->PosY->KeyFrames();	
	flags>>=1;
	if(flags&1)
		temp+=this->AxisX->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->AxisY->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->ScaleX->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->ScaleY->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->SkewX->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->SkewY->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->RotationAngle->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->Alpha->KeyFrames();
		flags>>=1;
	if(flags&1)
		temp+=this->Visible->KeyFrames();
	qSort(temp);
	int i=0;
	for(int j=0;j!=temp.size();++j)
	{
		if(temp[j]!=temp[i])
		{
			++i;
			temp[i]=temp[j];
		}
	}
	temp.erase(temp.begin()+(i+1),temp.end());
	return temp;
}

void ContainerNode::removeKeyFrames(int flags,int time)
{
	if(flags&1)
		((AnimatePropertyNode*)(this->PosX))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->PosY))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->AxisX))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->AxisY))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->ScaleX))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->ScaleY))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->SkewX))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->SkewY))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->RotationAngle))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->Alpha))->RemoveKey(time);
	flags>>=1;
	if(flags&1)
		((AnimatePropertyNode*)(this->Visible))->RemoveKey(time);
}